﻿using DataEntity;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using UCore;

namespace Twin {
    public class Worker : IDisposable {
        private volatile bool fQuit;
        private readonly int iPort;
        private readonly TConsole tc;
        private readonly Channel channel;
        private Thread threadRx;

        public static _Func m_dll = new _Func();
        public static ConcurrentDictionary<string, string> mapMarking = new ConcurrentDictionary<string, string>();



        // 定义事件委托（带解析后的结构化数据参数）
        public delegate void DataParsedEventHandler(string sNow);
        public static event DataParsedEventHandler OnDataParsed;



        public Worker(bool fQuit, int iPort, TConsole tc) {
            this.fQuit = fQuit;
            this.iPort = iPort;
            this.tc = tc;
            this.channel = TConsole.channel[iPort];

            thread_Worker(iPort);
        }


        private void thread_Worker(int iPort) {
            threadRx = new Thread(ProcWorker) {
                Name = $"WorkerThread-Port{iPort}",
                IsBackground = true
            };
            threadRx.Start();
        }


        private void ProcWorker() {
            try {
                while (!fQuit) {
                    if ((bool)tc.list_lvChannelIn[iPort].Tag) {
                        Thread.Sleep(10);
                        continue;
                    }

                    
                    //if (channel.countQueueIn() > 0 && channel.TryDequeue(out string txtBuf)) {
                    if (channel.countQueueIn() > 0) {
                        if (channel.TryDequeue(out string txtBuf)) {
                            string[] msg = null;
                            string memo = "";

                            msg = split_and_clean(txtBuf);
                            MergeAll(msg);

                            string s = m_dll.Parse("G_INFO", msg[0]);
                            if (string.IsNullOrEmpty(s)) {
                                Console.WriteLine("Error: Parsing: " + s);
                                continue;
                            }

                            try {
                                _Base.INFO_MSG Info = JsonConvert.DeserializeObject<_Base.INFO_MSG>(s);
                                if (Info != null) {
                                    memo = getMsgMemo(ref Info, msg.Length);
                                    showMsgs(tc.list_lvChannelIn[iPort], memo, txtBuf);
                                }
                            } catch (JsonException ex) {
                                Console.WriteLine("Error deserializing: " + ex.Message);
                            }
                        } else {
                            Console.WriteLine("Error tryDequeue");
                        }
                    } else {
                        Thread.Sleep(10);
                    }
                }
            } catch (Exception ex) {
                Console.WriteLine($"Error in worker thread for port {iPort}: {ex.Message}");
            } finally {
                Console.WriteLine($"Thread msg processing for port {iPort} stopped");
            }
        }


        public void set_fQuit(bool f) {
            fQuit = f;
            if (f && threadRx != null && threadRx.IsAlive) {
                threadRx.Join(100);
            }
        }


        public void Dispose() {
            set_fQuit(true);
        }


        public static string[] split_and_clean(string msgs) {
            string[] t = msgs.Split('_');
            for (int i = 0; i < t.Length; i++) {
                t[i] = t[i].Replace("!", "").Replace("_", "").Trim();
            }
            return t;
        }


        private void AreaDone(string kName, string sArea) {
            bool f = m_dll.doCheckPack(sArea);
            if (f) {
                //mapFilebuf.TryAdd(kName, sArea);
                Parsing.mapFile.AddOrUpdate(kName, sArea, (key, oldValue) => sArea);
                Parsing.save_AreasIni();
                //
                string jsonArea = Parsing.postAreaGotton(kName.Substring(2));
                tc.styleJson(jsonArea);
            } else {
                Console.WriteLine("Check pack false, sArea={1}", sArea);
            }
        }


        public void showMsg(TextBox textbox, string msg) {
            Action updateTextbox = () => {
                tc.txtExplicit.Text = msg;
            };

            // 在 UI 线程上执行更新操作
            if (tc.txtExplicit.InvokeRequired) {
                tc.txtExplicit.BeginInvoke(updateTextbox);
            } else {
                //updateTextbox();
                tc.txtExplicit.Text = msg;
            }
        }

        private void BlocDone(string kName, string sBloc) {
            //mapFilebuf.TryAdd(kName, sBloc);
            Parsing.mapFile.AddOrUpdate(kName, sBloc, (key, oldValue) => sBloc);
            //
            string filePath = Ini.path_Iap_bin;
            Parsing.save_Bloc(filePath, sBloc);

            string msg = kName + " in " + filePath;
            showMsg(tc.txtExplicit, msg);
        }


        private void OledDone(string kName, string sBloc) {
            //mapFilebuf.TryAdd(kName, sBloc);
            Parsing.mapFile.AddOrUpdate(kName, sBloc, (key, oldValue) => sBloc);
            //
            string filePath = Ini.path_Oled_gram;
            Parsing.save_Bloc(filePath, sBloc);

            string msg = kName + " in " + filePath;
            showMsg(tc.txtExplicit, msg);


            // 模拟主线程接收数据
            Oled oled = frmOled.oled;
            oled.ReceiveData(sBloc);
        }
        


        //进度条
        private void segProgressBar(_Base.INFO_SEG segParsed) {
            if (segParsed._SegIndex.Equals("0")) {
                // 使用 Invoke 确保在 UI 线程上更新 Maximum
                tc.progressBar.Invoke(new Action(() =>
                {
                    tc.progressBar.Maximum = int.Parse(segParsed._Segs);
                }));
            }
            // 更新进度条的值
            tc.progressBar.Invoke(new Action(() => {
                tc.progressBar.Value = int.Parse(segParsed._SegIndex);
            }));

            // 更新 Label 的文本内容以显示当前进度值
            tc.labelProgress.Invoke(new Action(() =>
            {
                tc.labelProgress.Text = $"{int.Parse(segParsed._SegIndex)}";
            }));
        }


        //合并
        public void MergeMsg(string sMsg) {
        
            int fCascade = m_dll.doIsCascade(sMsg);

            //组合segs
            if (fCascade == 1) {
                string jSeg = m_dll.Parse("G_PROFILE", sMsg);

                _Base.INFO_SEG segParsed = null;
                try {
                    segParsed = JsonConvert.DeserializeObject<_Base.INFO_SEG>(jSeg);
                } catch (Exception e) {
                    Console.WriteLine($"Error: {e.Message}");
                }

                //ProgressBar
                segProgressBar(segParsed);

                //doMerge
                string sRet = SegsMerge(segParsed);
                if (sRet == null) {
                    return; // Merge not completed, wait for subsequent messages
                }

                //file ready !
                string kName = Parsing.convertToFullName(segParsed._FileId);
                if (kName == null) {
                    Console.WriteLine("key == null, discard !");
                    return;
                }

                if (kName.Equals("IAP")) {
                    BlocDone(kName, sRet);
                }
                else if (kName.Equals("OLED_GRAM")) {
                    OledDone(kName, sRet);
                }
                else {
                    AreaDone(kName, sRet);
                }
            }

            //单Msg
            else {
                string jsonMsg = m_dll.Parse("G_INFO", sMsg);
                _Base.INFO_MSG infoParsed = JsonConvert.DeserializeObject<_Base.INFO_MSG>(jsonMsg);

                //unso-msg skip
                if (infoParsed._bInstDir == "1") return;


                //只显示响应
                if (tc.optProfile.Checked) {
                    jsonMsg = m_dll.Parse("G_PROFILE", sMsg);
                } else if (tc.optInstant.Checked) {
                    jsonMsg = m_dll.Parse("G_INSTANT", sMsg);
                } else if (tc.optDetail.Checked) {
                    jsonMsg = m_dll.Parse("G_DETAIL", sMsg);
                }
                tc.styleJson(jsonMsg);

                //判断_Sn是否匹配
                if (infoParsed._Sn.Equals(TConsole.SnMsg.ToString())) {
                    JObject data = JObject.Parse(jsonMsg);
                    string sNow = data["_Now"].ToString(); // "2019-12-2 6:29:30"
                    ReceiveData(sNow);
                }
            }
        }


        //Fill blanks, one by one.
        public static string SegsMerge(_Base.INFO_SEG segParsed) {
            string sExist;
            if (!mapMarking.TryGetValue(segParsed._FileId, out sExist)) {    //fileMap中：不存在的新文件
                sExist = InitMarking(segParsed);        //new
            } else {      //fileMap中存在的文件
                sExist = mapMarking[segParsed._FileId];
            }

            //replace "[xxx]" with s[]
            string sMark = "[" + segParsed._SegIndex + "]";
            int pos = sExist.IndexOf(sMark);
            if (pos < 0) {
                mapMarking.TryRemove(segParsed._FileId, out _);
                //TextOut.println(KGet.HHmmSS() + " Merge-mark" + sMark + " not found.");
                return null;
            }

            string sResult = sExist.Replace(sMark, segParsed._SegHex);
            //"[0][1][2] 487801...E74D [123][124]"

            // all : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", no "["
            if (sResult.IndexOf("[") < 0) {
                mapMarking.TryRemove(segParsed._FileId, out _);  //恢复到起始状态
                return sResult;                                 //Completed !
            } else {
                mapMarking[segParsed._FileId] = sResult;
            }
            return null;
        }


        // Init as : "[0][1][2] ... [123][124]"
        private static string InitMarking(_Base.INFO_SEG segParsed) {
            int size = int.Parse(segParsed._Segs);
            string s = "";
            for (int i = 0; i < size; i++) {
                s += "[" + i + "]";
            }
            //mapFilebuf.TryAdd(segParsed._FileId, s);
            mapMarking.AddOrUpdate(segParsed._FileId, s, (key, oldValue) => s);
            return s;
        }


        /*private void pushToMsgProcess(string[] msgs) {
            foreach (string msg in msgs) {
                if (string.IsNullOrWhiteSpace(msg)) continue;
                listMsg.Add(msg);
            }
            TConsole._resetEvent.Set();
        }*/


        public void MergeAll(string[] msgs) {
            foreach (string msg in msgs) {
                if (string.IsNullOrWhiteSpace(msg)) continue;
                //UCore.MsgQueue.AddMessage(msg); // 使用 MessageManager 添加消息
                MergeMsg(msg);
            }
        }


        private string getMsgMemo(ref _Base.INFO_MSG Info, int num) {
            string s = "收到";

            if (!string.IsNullOrEmpty(Info._Error)) {
                s += ":" + Info._Error;
                return s;
            }

            if (Info._bInstDir.Equals("1")) {
                s += "消息";
                if (Info._bCascade.Equals("1")) {
                    s += " 级联";
                }
                s += ",Sn=" + Info._Sn;
            } else {
                s += "响应";
                if (Info._bCascade.Equals("1")) {
                    s += " 级联";
                }
                s += ",Sn=" + Info._Sn;
            }

            if (num > 1) {
                s += "[" + num.ToString() + "]";
            }

            return s;
        }


        private void showMsgs(ListView lv, string memo, string txt) {
            if ((iPort < 0) || (iPort >= Ini.size_of.port)) {
                Console.WriteLine(txt);
                return;
            }

            try {
                Action appendItem = () => {
                    while (lv.Items.Count >= 128) {
                        lv.Items.RemoveAt(0);
                    }

                    ListViewItem lvi = new ListViewItem((DateTime.Now.ToString("MM-dd-yy HH:mm:ss") + " " + memo));
                    lvi.SubItems.Add(txt);
                    lv.Items.Add(lvi);
                    lv.EnsureVisible(lv.Items.Count - 1);
                };

                if (lv.InvokeRequired) {
                    lv.BeginInvoke(appendItem);
                } else {
                    appendItem();
                }
            } catch (ArgumentOutOfRangeException ex) {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }


        public static void ReceiveData(string sNow) 
        {
            if (OnDataParsed != null) {
                    var context = SynchronizationContext.Current;
                    if (context != null) {
                        context.Post(_ => OnDataParsed(sNow), null);
                    } else {
                        OnDataParsed(sNow);
                    }
                }
        }

    }
}